/* ----------------------------------------------------------------------------
   Copyright (C) 2010 One Laptop per Child

   This program is free software; you can redistribute it and/or modify it
   under the terms of the GNU General Public License as published by the
   Free Software Foundation; either version 2, or (at your option) any
   later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

   In other words, you are welcome to use, share and improve this program.
   You are forbidden to forbid anyone else to use, share and improve
   what you give them.   Help stamp out software-hoarding!

   As a special exception, you may use this file as part of a free software
   library for the XO of the One Laptop per Child project without restriction.
   Specifically, if other files instantiate
   templates or use macros or in-line functions from this file, or you compile
   this file and link it with other files to produce an executable, this
   file does not by itself cause the resulting executable to be covered by
   the GNU General Public License.  This exception does not however
   invalidate any other reasons why the executable file might be covered by
   the GNU General Public License.
-------------------------------------------------------------------------*/

/* ESD Warning

Its been discovered that ESD can cause the DS2756 to malfunction.
Sometimes the shadow ram for the EEPROM gets corrupted with a series of 0xffs.
In general these don't cause any serious problems for LiFePO4 which does not
use most of the values stored in the EEPROM.  When a battery is inserted we
scan the shadow ram for a string of >= 4 0xffs and if we find one then we issue
a recall from the EEPROM reset the ram back to sane values.

The one exception is the default status register ( offset 0x31).  This value
is loaded into the status register on power up or on a bank 0 commit.
Bit 0 of this register is the high-speed bit or overdrive timing.  This radically
changes the timing of the 1-wire bus.  In this mode we can't talk to the gauge.
Therefore the code tries to prevent the default status register from byte
from ever getting set with a value different than 0x6a.

The 2nd issue is that snapshot mode will get enabled.  Normally you have to send a
0xD2 command to the gauge to enable snapshot but somehow ESD can enable it as well.
So if we find a different value in the special function register on insert then we
reset that as well.

*/

#define W1_SHOW_STATE	0

#include <stdio.h>
#include "cc_compat.h"
#include "chip.h"
#include "ds2756.h"
#include "onewirebatt.h"
#include "lifebatt.h"
#include "io.h"
#include "timer.h"
#include "sdi.h"
#include "event.h"
#include "battery.h"
#include "ac.h"
#include "mppt.h"
#include "power.h"

#define STATUS_REG            0x01
#define EEPROM_REG            0x07
#define SPECIAL_FEATURE_REG   0x08
#define VOLTAGE_MSB_REG       0x0C
#define VOLTAGE_LSB_REG       0x0D
#define CURRENT_MSB_REG       0x0E
#define CURRENT_LSB_REG       0x0F
#define ACC_CURRENT_MSB_REG   0x10
#define ACC_CURRENT_LSB_REG   0x11
#define TEMPERATURE_MSB_REG   0x18
#define TEMPERATURE_LSB_REG   0x19
#define AVE_CURRENT_MSB_REG   0x1A
#define AVE_CURRENT_LSB_REG   0x1B
#define EEPROM_BANK0_INDEX    0x20
#define EEPROM_BANK1_INDEX    0x40
#define EEPROM_BANK2_INDEX    0x60
#define SRAM_INDEX            0x80

#define W1OPREAD  0x01
#define W1OPWRITE 0x02

#define cABNORMAL 0x08

unsigned char xdata onewire_enabled;

unsigned char xdata OneBattInfor[32];

unsigned char xdata g_bUpdate;

unsigned char xdata bProcessOneWireIndex;
unsigned char xdata bOneWireBattery;
unsigned char xdata bPinState;
unsigned char xdata bCommandIndex;
unsigned char xdata bCmdBuffer;
unsigned char xdata bRecByteCnt;
unsigned char xdata bRecByte;
unsigned char xdata bW1bitMask;
unsigned char xdata bW1DatBuf;
unsigned char xdata bW1Operation;

unsigned char xdata bPollCheckCounter;
unsigned char xdata bAbnormalCauseCode;

unsigned char code * xdata wOneWireTablePtr;

unsigned char xdata bWriteCheckCache[32];

unsigned char xdata bDataLength;
unsigned char xdata bBatSRAMIndex;
unsigned char xdata bDataLengthBackUp;
unsigned char xdata bWriteDataLength;

unsigned char xdata BATT_TEMP_ACR[2];
unsigned char xdata BATT_TEMP_DCR[2];
unsigned int  xdata BATT_ERR_CHECK;
unsigned char xdata BATT_SIGN_DATA;
unsigned char xdata bEEPROM_WRITE_ALL;
unsigned char xdata bBATT_RETRY_CNT;
unsigned int  xdata wEEPROM_WR_TIME;
unsigned char xdata bBATT_IN_DEBOUNCE;
unsigned char xdata BATT_TEMP_REAL_ACR[2];
unsigned char xdata bErrorCheckCounter;
unsigned char xdata bPollCheckCounter;
unsigned char xdata read_counter;

unsigned char xdata bBattDataFfCount;
unsigned char xdata bBattBusStackAt0Cnt;

unsigned char xdata w1_state_index;

unsigned char xdata SOC;
unsigned char xdata NewACR_BackUp_MSB;
unsigned char xdata NewACR_BackUp_LSB;

#ifdef NOT_USEFUL
unsigned char xdata BvOverride;
unsigned int  xdata BvValue;
#endif

unsigned char xdata GAUGE_CACHE[144+8];

unsigned char xdata bHDQ_ACCESS_FLAG;
unsigned char xdata bHDQ_ACCESS_FLAG1;

unsigned char xdata sMBAT_MISC;
#define         force_chgA      (1<<0)   // 1: charge first battery by host request
#define         force_discA     (1<<1)   // 1: discharge first battery by host request
#define         bat_update_all  (1<<2)   // 1: update the battery INFO (+++ DAVID +++)
#define         bat_next        (1<<3)   // 1: next use first battery
#define         bat_inUSE       (1<<4)   // 1: first battery connected to SMB
#define         bat_AutoLearn   (1<<5)   // 1: auto learning in progress
#define         bat_ValidFull   (1<<6)   // 1: battery real full
#define         bat_LiHi        (1<<7)   // 1: high capacity Li-Ion battery

int	xdata Pb_inst_in_mW;
long	xdata Ib_inst_in_mA;
long	xdata Vb_inst_in_mV;

static int	min_battery_power;
static int	max_battery_power;
static int	host_suspend_power;

/* ------------------------ DEFINE ----------------------------------------- */
#define W1_IDLE					0x00
#define PRESENCE_PULSE  		0x01
#define POLL_DATA_INDEX 		0x02
#define NO_PRESENCE_PULSE		0x03
#define HDQ_STOP        		0x04
#define W1_UPDATE_EC_CACHE		0x05
#define EEPROM_BNK0_INDEX 		0x06
#define EEPROM_BNK1_INDEX 		0x07
#define EEPROM_BNK2_INDEX 		0x08
//#define BATT_DCR_INDEX			0x09
#define WAIT_WRITE_DATA			0x0A
#define BATT_REMAIN_ACR_INDEX	0x0B
#define WAIT_WRITE_ACR  		0x0C
//#define ISSUE_BAT_IN    		0x0D  // Unused so removed
#define BUS_WAIT_STATE  		0x0E
//#define DUMP_DATA_REG   		0x0F
#define EEPROM_INIT_INDEX		0x10
#define NET_ADDRESS_INDEX		0x11
#define UPDATE_NET_ADDRESS		0x12
#define WAIT_BATT_DATA  		0x13
#define GOT_PRESENCE_PULSE		0x14
#define BATTERY_WAS_REMOVED		0x15

#define EEPROM_BNK0     		0x20
#define NET_ADDRESS				0x33			// RNAOP = 0
#define EEPROM_BNK1     		0x40
#define COPY_DATA       		0x48
#define EEPROM_BNK2     		0x60
#define READ_DATA       		0x69
#define LOCK_ROM        		0x6A
#define WRITE_DATA      		0x6C
#define SIGN_DATA       		0x7F

//#define BATT_SIGNED_INDEX 		0x81
//#define MAKE_SIGNED_BATT  		0x82
#define WAIT_WRITE_DCR  		0x83
#define WAIT_WRITE_BNK0 		0x84
#define WAIT_WRITE_BNK1 		0x85
#define WAIT_WRITE_BNK2 		0x86
#define CHK_SER_NO      		0x87
#define READ_ALL_BLOCK  		0x88
#define READ_TWO_BLOCK  		0x89
#define EEPROM_BNK21_INDEX 		0x8A
#define UPDATE_BATT_DATA 		0x8B
#define UPDATE_REAL_ACR  		0x8C
#define WAIT_WRITE_REAL_ACR 	0x8D
#define COMPARE_ACR     		0x8E
//#define COMPARE_BANK			0x8F
#define WAIT_WRITE_REINIT		0x90
#define CALC_MOVING_AVG			0x91
#define W1_CHECK_DATA_VALID1	0x92
#define UPDATE_BATT_DATA2		0x93
#define BATTERY_ERROR_STATE		0x94
#define W1_CHECK_READING_VALID	0x95
#define VALIDATE_BANK0			0x96
#define VALIDATE_BANK1			0x97
#define VALIDATE_BANK2			0x98
#define SEED_AVERAGES			0x99
#define BATTERY_VALID			0x9a
#define BANK0_RECALL_DONE		0x9b
#define BANK1_RECALL_DONE		0x9c
#define BANK2_RECALL_DONE		0x9d
#define READ_REGS_INDEX			0x9e
#define WRITE_REGS_INDEX		0x9f
#define BACKUP_ACR_INDEX 		0xA0
#define BACKUP_LAST_ACR  		0xA1
#define LAST_ACR_INDEX   		0xA2
#define WAIT_LAST_ACR_UPDATE 	0xA3
// #define SET_DATA_INDEX		0xA4
#define WAIT_WRITE_REGS			0xa5
#define VALIDATE_REGS			0xa6
#define ONEWIRE_HANG			0xa7
#define WAIT_BATT_DATA_COMPLETE 0xa8

#define RECALL_DATA     		0xB8
#define SKIP_NET_ADDR   		0xCC

#define EEPROM_WRITE_LOOPS		39000		// Roughly every 65 minutes at 100ms per op.
#define W1_OP_DELAY				150

/*---------------------------------------------------------------------------*/
/* DEFINE TABLES for HDQ PROCESS */
// index code 0x01;
static unsigned char code READ_NET_ADDRESS[]  =
{
	W1_IDLE,
	PRESENCE_PULSE, NET_ADDRESS, NET_ADDRESS_INDEX,
	WAIT_BATT_DATA, BUS_WAIT_STATE, UPDATE_NET_ADDRESS
	// UPDATE_NET_ADDRESS transfers to CHECK_REG_SETTINGS[]
};

// index code 0x02;
static unsigned char code READ_SERIAL_NO[]    =
{
	W1_IDLE,
	PRESENCE_PULSE,SKIP_NET_ADDR,READ_DATA,EEPROM_BNK21_INDEX,WAIT_BATT_DATA,
	PRESENCE_PULSE,W1_UPDATE_EC_CACHE,CHK_SER_NO,READ_TWO_BLOCK,
	HDQ_STOP
};

// index code 0x03
static unsigned char code BACKUP_REAL_ACR[]   =
{
	W1_IDLE,
	PRESENCE_PULSE,SKIP_NET_ADDR,READ_DATA,BACKUP_ACR_INDEX,WAIT_BATT_DATA,
	BACKUP_LAST_ACR,
	HDQ_STOP
};

// index  code 0x04
static unsigned char code WRITE_LAST_ACR[]    =
{
	W1_IDLE,
	PRESENCE_PULSE,SKIP_NET_ADDR,WRITE_DATA,LAST_ACR_INDEX,WAIT_LAST_ACR_UPDATE,
	BUS_WAIT_STATE,
	HDQ_STOP
};

// index code 0x05
static unsigned char code RECALL_EEPROM2RAM[] =
{
	W1_IDLE,
	PRESENCE_PULSE,SKIP_NET_ADDR,RECALL_DATA,EEPROM_BNK0_INDEX,BUS_WAIT_STATE,BUS_WAIT_STATE,
	PRESENCE_PULSE,SKIP_NET_ADDR,RECALL_DATA,EEPROM_BNK1_INDEX,BUS_WAIT_STATE,BUS_WAIT_STATE,
	PRESENCE_PULSE,SKIP_NET_ADDR,RECALL_DATA,EEPROM_BNK2_INDEX,BUS_WAIT_STATE,BUS_WAIT_STATE,
	READ_ALL_BLOCK,
	HDQ_STOP
};

// index code 0x06
static unsigned char code BATT_HDQ_POLL[] =
{
	W1_IDLE,
	PRESENCE_PULSE,SKIP_NET_ADDR,READ_DATA,POLL_DATA_INDEX,WAIT_BATT_DATA,
	PRESENCE_PULSE,W1_CHECK_READING_VALID,
//	After this these states are self directed.
//	So only call inc_command_index() when ready to end this series of states.
//	UPDATE_BATT_DATA,UPDATE_BATT_DATA2,CALC_MOVING_AVG,
	HDQ_STOP
};

// index code 0x07
static unsigned char code READ_EEPROM_BNK0[] =
{
	W1_IDLE,
	PRESENCE_PULSE,SKIP_NET_ADDR,READ_DATA,EEPROM_BNK0_INDEX,WAIT_BATT_DATA,
	PRESENCE_PULSE,W1_UPDATE_EC_CACHE,BUS_WAIT_STATE,
	HDQ_STOP
};

// index code 0x08
static unsigned char code READ_EEPROM_BNK1[] =
{
	W1_IDLE,
	PRESENCE_PULSE,SKIP_NET_ADDR,READ_DATA,EEPROM_BNK1_INDEX,WAIT_BATT_DATA,
	PRESENCE_PULSE,W1_UPDATE_EC_CACHE,BUS_WAIT_STATE,
	HDQ_STOP
};

// index code 0x09
static unsigned char code READ_EEPROM_BNK2[] =
{
	W1_IDLE,
	PRESENCE_PULSE,SKIP_NET_ADDR,READ_DATA,EEPROM_BNK2_INDEX,WAIT_BATT_DATA,
	PRESENCE_PULSE,W1_UPDATE_EC_CACHE,BUS_WAIT_STATE,
	HDQ_STOP
};

// index code 0x0a
// index code 0x16;
static unsigned char code WRITE_EEPROM_BNK0[] =
{
	W1_IDLE,
	PRESENCE_PULSE,SKIP_NET_ADDR,WRITE_DATA,EEPROM_BNK0_INDEX,WAIT_WRITE_BNK0,
	BUS_WAIT_STATE, BUS_WAIT_STATE,
	HDQ_STOP
};
// index code  0x0b
// index code  0x17
static unsigned char code WRITE_EEPROM_BNK1[] =
{
	W1_IDLE,
	PRESENCE_PULSE,SKIP_NET_ADDR,WRITE_DATA,EEPROM_BNK1_INDEX,WAIT_WRITE_BNK1,
	BUS_WAIT_STATE, BUS_WAIT_STATE,
	HDQ_STOP
};
// index code 0x0c
// index code 0x18
static unsigned char code WRITE_EEPROM_BNK2[] =
{
	W1_IDLE,
	PRESENCE_PULSE,SKIP_NET_ADDR,WRITE_DATA,EEPROM_BNK2_INDEX,WAIT_WRITE_BNK2,
	BUS_WAIT_STATE, BUS_WAIT_STATE,
	HDQ_STOP
};

// index code 0x0d
static unsigned char code WRITE_BATT_ACR[] =
{
	W1_IDLE,
	PRESENCE_PULSE,SKIP_NET_ADDR,WRITE_DATA,BATT_REMAIN_ACR_INDEX,WAIT_WRITE_ACR,BUS_WAIT_STATE,
	BUS_WAIT_STATE,
	HDQ_STOP
};
// index code 0x0e
static unsigned char code COMPARE_ACR_VALUE[] =
{
	W1_IDLE,
	PRESENCE_PULSE,SKIP_NET_ADDR,READ_DATA,BATT_REMAIN_ACR_INDEX,WAIT_BATT_DATA,COMPARE_ACR,
	BUS_WAIT_STATE,
	HDQ_STOP
};

// index code 0x12
static unsigned char code WRITE_BATT_REAL_ACR[] =
{
	W1_IDLE,
	PRESENCE_PULSE,SKIP_NET_ADDR,WRITE_DATA,UPDATE_REAL_ACR,WAIT_WRITE_REAL_ACR,
	BUS_WAIT_STATE,
	HDQ_STOP
};

// index code 0x14
static unsigned char code COPY_ALL_EEPROM[] =
{
	W1_IDLE,
	PRESENCE_PULSE,SKIP_NET_ADDR,COPY_DATA,EEPROM_BNK0_INDEX,BUS_WAIT_STATE,BUS_WAIT_STATE,
	PRESENCE_PULSE,SKIP_NET_ADDR,COPY_DATA,EEPROM_BNK1_INDEX,BUS_WAIT_STATE,BUS_WAIT_STATE,
	PRESENCE_PULSE,SKIP_NET_ADDR,COPY_DATA,EEPROM_BNK2_INDEX,BUS_WAIT_STATE,BUS_WAIT_STATE,
	HDQ_STOP
};

// index code 0x15
static unsigned char code CHECK_REG_SETTINGS[]	=
{
	W1_IDLE,
	PRESENCE_PULSE,SKIP_NET_ADDR,READ_DATA,READ_REGS_INDEX,WAIT_BATT_DATA,VALIDATE_REGS,
	HDQ_STOP
};
// unsigned char code REINIT_NIMH_EEPROM[] = { W1_IDLE,PRESENCE_PULSE,SKIP_NET_ADDR,WRITE_DATA,EEPROM_INIT_INDEX, HDQ_STOP};

// index code 0x16, 17, 18, 19 used by in code states

// index code 0x1a
static unsigned char code BATTERY_ERROR[]	=
{
	W1_IDLE,
	PRESENCE_PULSE,
	HDQ_STOP
};

// index code 0x1b
static unsigned char code STARTUP_READ[] =
{
	W1_IDLE,
	PRESENCE_PULSE,SKIP_NET_ADDR,READ_DATA,POLL_DATA_INDEX,WAIT_BATT_DATA,SEED_AVERAGES,
	PRESENCE_PULSE,SKIP_NET_ADDR,READ_DATA,EEPROM_BNK0_INDEX,WAIT_BATT_DATA,VALIDATE_BANK0,
	PRESENCE_PULSE,SKIP_NET_ADDR,READ_DATA,EEPROM_BNK1_INDEX,WAIT_BATT_DATA,VALIDATE_BANK1,
	PRESENCE_PULSE,SKIP_NET_ADDR,READ_DATA,EEPROM_BNK2_INDEX,WAIT_BATT_DATA,VALIDATE_BANK2,
	BATTERY_VALID,
	HDQ_STOP
};

// index code 0x1c
static unsigned char code RECALL_BANK0[] =
{
	W1_IDLE,
	PRESENCE_PULSE,SKIP_NET_ADDR,RECALL_DATA,EEPROM_BNK0_INDEX,BUS_WAIT_STATE,BUS_WAIT_STATE, BANK0_RECALL_DONE,
	HDQ_STOP
};

// index code 0x1d
static unsigned char code RECALL_BANK1[] =
{
	W1_IDLE,
	PRESENCE_PULSE,SKIP_NET_ADDR,RECALL_DATA,EEPROM_BNK1_INDEX,BUS_WAIT_STATE,BUS_WAIT_STATE, BANK1_RECALL_DONE,
	HDQ_STOP
};

// index code 0x1e
static unsigned char code RECALL_BANK2[] =
{
	W1_IDLE,
	PRESENCE_PULSE,SKIP_NET_ADDR,RECALL_DATA,EEPROM_BNK2_INDEX,BUS_WAIT_STATE,BUS_WAIT_STATE, BANK2_RECALL_DONE,
	HDQ_STOP
};

// index code 0x1f
static unsigned char code FIX_REGS[]	=
{
	W1_IDLE,
	PRESENCE_PULSE,SKIP_NET_ADDR,WRITE_DATA,WRITE_REGS_INDEX,WAIT_WRITE_REGS,BUS_WAIT_STATE,
	HDQ_STOP
};

/* ------------------------ VARIABLES -------------------------------------- */
unsigned char g_nOldSOC;
static unsigned char get_next_cmdindex;
static unsigned char error_bank;

static int g_nFFAbnormalCount;
static int w1_operation_timer;

static unsigned char one_wire_index_prev;
static unsigned char process_w1_index_prev;
static unsigned char show_state_switches;
static unsigned char onewire_do_show_states;

/* ------------------------ MODULES ---------------------------------------- */
void InitOneWireBus(void);
static void AccessBattery(void);
static void update_cache_values(void);

static unsigned char check_reading_valid(void);
static unsigned char check_bank0(void);
static unsigned char check_bank1(void);
static unsigned char check_bank2(void);

unsigned char   xdata MovingAvgCtr;
unsigned int    xdata wBAT_VOLTAGE;
signed  int     xdata wBAT_CURRENT;
signed  int     xdata wBAT_TEMPERATURE;
//signed  int     wBAT_ACR;
int				xdata onewire_loop_timer;

/*------------------------------------------------------------------------------
name : calcMovingAvg
------------------------------------------------------------------------------*/
#define AVG_DEPTH 8
void calcMovingAvg(void)
{
	static long volt_avg;
	static signed long curt_avg, temp_avg;

	int newVolt;
	signed int newCurt, newTemp;

	newVolt = GAUGE_CACHE[DS_VOLT_MSB];
	newVolt = ( newVolt << 8 )+ GAUGE_CACHE[DS_VOLT_LSB];
	newCurt = GAUGE_CACHE[DS_CURT_MSB];
	newCurt = ( newCurt << 8 ) + GAUGE_CACHE[DS_CURT_LSB];
	newTemp = GAUGE_CACHE[DS_TEMP_MSB];
	newTemp = ( newTemp << 8 ) + GAUGE_CACHE[DS_TEMP_LSB];

	Ib_inst_in_mA = ((long)newCurt * 15625L) / 120000L;
	Vb_inst_in_mV = ((long)newVolt * 488L) / 1600L;
	Pb_inst_in_mW = (int) (Ib_inst_in_mA * Vb_inst_in_mV / 1000L);

	if (Pb_inst_in_mW < min_battery_power) min_battery_power = Pb_inst_in_mW;
	if (Pb_inst_in_mW > max_battery_power) max_battery_power = Pb_inst_in_mW;
	// If the host is supened then updated the suspend power reading
	if (host_in_suspend())
	{
		host_suspend_power = Pb_inst_in_mW;
	}

	if ( MovingAvgCtr == 0 )
	{
		// initial value for average is AVG_DEPTH * the first sample value
		// to seed the filter
		volt_avg = (long)newVolt * AVG_DEPTH;
		curt_avg = (long)newCurt * AVG_DEPTH;
		temp_avg = (long)newTemp * AVG_DEPTH;
		MovingAvgCtr = AVG_DEPTH;  // unused, except as flag
	}
	else
	{
		volt_avg = volt_avg - (volt_avg / AVG_DEPTH) + newVolt;
		curt_avg = curt_avg - (curt_avg / AVG_DEPTH) + newCurt;
		temp_avg = temp_avg - (temp_avg / AVG_DEPTH) + newTemp;
	}

	wBAT_VOLTAGE = volt_avg / AVG_DEPTH;
	wBAT_CURRENT = curt_avg / AVG_DEPTH;
	wBAT_TEMPERATURE = temp_avg / AVG_DEPTH;
}

/*
 * Name: SetAbnormalCauseCode
 * Desc: Set abnormal code and cause SCI event
 */
void SetAbnormalCauseCode( unsigned char nCode )
{
	printf("Batt Error: 0x%x\n", (unsigned int)nCode);
	bAbnormalCauseCode = nCode;
	sMBAT_STATUS |= bat_error;
	event_send_event(EVENT_BATTERY_ERROR);
	battery_set_leds_state(LEDS_STATE_ERROR);
}

unsigned char w1_intval;

void intsrv_timer1(void) interrupt 3
{

	TR1 = 0;
	if (bW1Operation != 0)
	{
		TL1 = 0x50;
		TH1 = 0xff;
		TR1 = 1;
	}
	DQ_RELEASE;

	if (bW1Operation == W1OPREAD)	//Is it in read cycle?
	{
		/* read cycle */
		// Minimum low time for a read is 1us.  Asserting the signal
		// low twice will provide enough delay.
		DQ_DRIVELOW;
		DQ_DRIVELOW;
		DQ_RELEASE;

#ifdef SDCC
		__asm
		nop
		nop
		__endasm;
#else
		_nop_();
		_nop_();
#endif

		bW1DatBuf >>= 1;            //shift next bit and set 0
		if (DQ_HIGH)				//Is data high
			bW1DatBuf |= 0x80;		//set bit 1
		bW1bitMask <<= 1;			//shift bit mask
	}
	else if (bW1Operation == W1OPWRITE)
	{
		DQ_DRIVELOW;
		// Tlow1 min on the bus is 1us so the if() check
		// provides enough delay
		if (bW1DatBuf & bW1bitMask)     // Write 1
		{
			DQ_RELEASE;
		}
		bW1bitMask <<= 1;
	}

	if (bW1bitMask == 0)
	{
		if (bW1Operation == W1OPREAD)
		{
			OneBattInfor[bRecByteCnt] = bW1DatBuf;
			bRecByteCnt++;
		}
		bW1Operation = 0x00;
		// if timeout then Command Index = 0;
	}
}

/* One wire send byte */
void OneWireSendByte(unsigned char Byte)
{
	bW1DatBuf = Byte;
	bW1bitMask = 0x01;
	TL1 = 0xC0;
	TH1 = 0xFF;
	TR1 = 1;
	bW1Operation = W1OPWRITE;
}

/* One wire receive data byte */
void OneWireRecByte(void)
{
	bW1bitMask = 0x01;
	TL1 = 0xC0;
	TH1 = 0xFF;
	TR1 = 1;
	bW1Operation = W1OPREAD;
}

/*-----------------------------------------------------------------------------
 Name : HDQ_POLL_BATT_DATA
-----------------------------------------------------------------------------*/
static void HDQ_POLL_BATT_DATA(unsigned char code * ptr)
{
	/* assign pointer for HDQ table */
	wOneWireTablePtr = ptr;
	bCommandIndex = 0;
}

void onewire_process(void)
{
	if (!onewire_enabled) return;

	/*
	 * You cannot run this state machine any faster than the time it
	 * takes to do a single byte onewire transaction on the one wire bus.
	 * ie (Tslot * 8 bits).  The reason is that the one wire send  and
	 * receive routines have no synchronization with when the bus is finished
	 * they expect the transaction to be complete on the next iteration
	 *
	 * FIXME:  One the conversion to hardare OWM fix this
	 *
	*/
	if (!check_timer(onewire_loop_timer,5)) return;

	onewire_loop_timer = get_ms_timer();

	if (bOneWireBattery == 0)
	{
		/* no battery exist before */
		switch (bProcessOneWireIndex)
		{
				// Valid states for the presence detect
			case W1_IDLE:
			case PRESENCE_PULSE:
			case POLL_DATA_INDEX:
			case NO_PRESENCE_PULSE:
			case GOT_PRESENCE_PULSE:
			case BATTERY_WAS_REMOVED:
				break;

			default:
				bProcessOneWireIndex = 0;
		}
		bCommandIndex = 0;
	}
	else
	{
		/* normal polling process */
		if (get_next_cmdindex)
		{
			bProcessOneWireIndex = wOneWireTablePtr[bCommandIndex];
			get_next_cmdindex = 0;
		}
	}
	AccessBattery();
}

// Cold boot init.  OneWireInit is called when
// we wake from deep sleep
void onewire_init_module(void)
{
//	show_state_switches = 0;
	// Set it to something different than 0x00 so you
	// can see the first change.
	one_wire_index_prev = 0xff;
	process_w1_index_prev = 0xff;
	battery_info &= ~BATTERY_VALID_FLAG;
	battery_info &= ~BATTERY_VALID_PREV;
//	sMBAT_STATUS		= 0;
//	sMCHARGE_STATUS		= 0;
//	bHDQ_ACCESS_FLAG	= 0;
//	bHDQ_ACCESS_FLAG1	= 0;
//	onewire_loop_timer	= 0;
//	onewire_do_show_states		= 0;
	min_battery_power = 32000;
	max_battery_power = -32000;
	onewire_init();
}

#ifdef UNUSED
unsigned char onewire_is_enabled(void)
{
	return onewire_enabled;
}
#endif

void onewire_enable(void)
{
	onewire_enabled = 1;
	onewire_loop_timer = get_ms_timer();
}

#ifdef UNUSED
void onewire_disable(void)
{
	onewire_enabled = 0;
}
#endif

void onewire_init(void)
{
	TR1=0;
	TMOD = (TMOD&0x0f)|0x10;
	TF1=0;
	ET1=1;
	bW1Operation = 0x00;
}

void onewire_init_bus(void)
{
	/* make HDQ free */
	DQ_RELEASE;
	bCommandIndex = 0;
	w1_operation_timer = get_ms_timer();
	get_next_cmdindex = 1;
	// bBAT_DeBugFlag4 = LIFE_DEBUG_DEFAULT;
	bPollCheckCounter = 0;
}

static void inc_command_index(void)
{
	bCommandIndex++;
	get_next_cmdindex = 1;
}

void onewire_debug_dump(void)
{
	print_tstamp();
	printf("w1state = %x,%x\n",(unsigned int)w1_state_index,
		   (unsigned int) bProcessOneWireIndex);

}

void onewire_enable_show_states(void)
{
	onewire_do_show_states = 1;
}
/*-----------------------------------------------------------------------------
 Name : AccessBattery
-----------------------------------------------------------------------------*/
static void AccessBattery(void)
{
	/* polling step and follow DQ2756 spec */
	unsigned char presence_pulse=0;
	unsigned char i;
	// State switch debugging code
#if W1_SHOW_STATE
	if (one_wire_index_prev != w1_state_index)
	{
		show_state_switches = 1;
		one_wire_index_prev = w1_state_index;
	}

	if (show_state_switches)
	{
		if (process_w1_index_prev != bProcessOneWireIndex)
		{
			onewire_debug_dump();
			process_w1_index_prev = bProcessOneWireIndex;
		}
	}
#endif

	DQ_RELEASE;
	switch (bProcessOneWireIndex)
	{
			/* first step in reset pulse */
		case W1_IDLE:
			// 1wire operations are run after this delay
			// when they run they run to completion.
			// hang out here until it's time to run

			// If you adjust the idle delay time then you also have
			// to adjust the number of EEPROM_WRITE_LOOPS to match your
			// new loop time.
			if (check_timer(w1_operation_timer,W1_OP_DELAY))
			{
				w1_operation_timer = get_ms_timer();
				bProcessOneWireIndex = PRESENCE_PULSE;
				inc_command_index();
				wEEPROM_WR_TIME++;
			}
			break;

		case PRESENCE_PULSE:
			DQ_DRIVELOW;	/* reset_pulse */
			usec_delay(500);	// approx 500 us delay
			DQ_RELEASE;
			usec_delay(30);	// tPDH is 15 to 60us. This should put
			// us into where the presence pulse should occur.
			// Watch for a presence pulse. Should be between 60us and 240us
			for (i=0; i<200; i++)
			{
				if (DQ_LOW)
				{
					presence_pulse=1;
					break;
				}
			}

			if (presence_pulse)
			{
				bProcessOneWireIndex = GOT_PRESENCE_PULSE;
			}
			else // if (presence_pulse)
			{
				bProcessOneWireIndex = NO_PRESENCE_PULSE;
			}

			break;

		case NO_PRESENCE_PULSE:
			/* battery no ACK or disconnect */
			bOneWireBattery = 0;
			bCommandIndex = 0;      // retry battery bus
			bW1Operation = 0;
			bBattBusStackAt0Cnt = 0;

			if (bBATT_RETRY_CNT == 0)
			{
				if ((sMBAT_STATUS & bat_in) != 0)
				{
					puts("Bat out");
				}
				/* retry three times */
				if (BATT_ERR_CHECK != 0xFFFF)
					BATT_ERR_CHECK++;
				bAbnormalCauseCode 	= 0;
				GAUGE_CACHE[DS_VOLT_MSB] = 0;
				GAUGE_CACHE[DS_VOLT_LSB] = 0;
				GAUGE_CACHE[DS_CURT_MSB] = 0;
				GAUGE_CACHE[DS_CURT_LSB] = 0;
				sMBAT_STATUS &= ~bat_in;
				sMBAT_STATUS &= ~bat_low;
				sMBAT_STATUS &= ~bat_error;
				sMCHARGE_STATUS &= ~bat_WakeChg;
				sMCHARGE_STATUS &= ~bat_charge;
				bHDQ_ACCESS_FLAG = 0;
				bHDQ_ACCESS_FLAG1 = 0;
				bEEPROM_WRITE_ALL = 0;
				bBATT_IN_DEBOUNCE = 0;
				battery_info &= ~BATTERY_VALID_FLAG;
				bProcessOneWireIndex = W1_IDLE;
			}
			else
			{
				bBATT_RETRY_CNT--;
				bProcessOneWireIndex = PRESENCE_PULSE;
			}

			w1_state_index = 0;
			show_state_switches = 0;
			break;

		case GOT_PRESENCE_PULSE:
			/* Has the battery been removed ? */
			if (((sMBAT_STATUS & bat_in) == 0) && (bOneWireBattery == 0))
			{
				bProcessOneWireIndex = BATTERY_WAS_REMOVED;
			}
			else
			{
				if (bOneWireBattery == 0)
				{
					/* one wire interface disconnect */
					bEEPROM_WRITE_ALL = 0;
					bCommandIndex = 0;      // retry battery bus
					bOneWireBattery = 1;
					bProcessOneWireIndex = PRESENCE_PULSE;
					break;
				}
				// If we have errored then just wait for removal.
				if ((sMBAT_STATUS & bat_error) != 0)
				{
					// Jump to a state so you can see this in the
					// see-bstate debug logs
					bProcessOneWireIndex = BATTERY_ERROR_STATE;
					break;
				}
				// Otherwise move on
				inc_command_index();
			}

			bBATT_RETRY_CNT = 5;

			break;

		case BATTERY_WAS_REMOVED:
			/* no battery in before, means battery just plug in */
			if (bBATT_IN_DEBOUNCE > 0)
			{
				/* Is battery debounced */
				sMCHARGE_STATUS &= ~bat_wakeup;
				GAUGE_CACHE[DS_BAT_INFO] = 0;

				inc_command_index();
				HDQ_POLL_BATT_DATA( READ_NET_ADDRESS );
				w1_state_index = 0x01;

				// --- DAVID
				bBATT_IN_DEBOUNCE = 210;
				bErrorCheckCounter = 0;
				bPollCheckCounter = 0;
				g_nOldSOC	= 0;
				/* Hsin 2007/02/13 ++ */
				/*i the routine is for bus stuck at zero checking */
				/* From the spec the bus should be free axfter 60us */
				usec_delay(100);
				if (read_DQ() == 0)
				{
					/* the bus stuck at 0 */
					bOneWireBattery = 0;
					bBATT_IN_DEBOUNCE = 0;
					bBattBusStackAt0Cnt++;
				}
				else
				{
					/* battery bus is free now */
					bBattBusStackAt0Cnt = 0;
					bOneWireBattery = 1;
				}
				if (bBattBusStackAt0Cnt > 10)
				{
					SetAbnormalCauseCode( BATT_ERR_1W_STUCK_LOW );
					bProcessOneWireIndex = BATTERY_ERROR_STATE;
				}
			}
			else
			{
				/* in debouncing */
				bBATT_IN_DEBOUNCE++;
				bOneWireBattery = 0;
				bProcessOneWireIndex = PRESENCE_PULSE;
			}
			wEEPROM_WR_TIME = 0;
			break;

		case CHK_SER_NO:  /* battery serial number checking */
			inc_command_index();
			BATT_SIGN_DATA = 0x55;
			if ((GAUGE_CACHE[DS_BAT_SERIAL_NUM_1] == 0)&&(GAUGE_CACHE[DS_BAT_SERIAL_NUM_2] == 0)
					&&(GAUGE_CACHE[DS_BAT_SERIAL_NUM_3] == 0)&&(GAUGE_CACHE[DS_BAT_SERIAL_NUM_4] == 0)
					&&(GAUGE_CACHE[DS_BAT_SERIAL_NUM_5] == 0))
			{
				/* here is for no serial number to be read, maybe very low voltage */
				BATT_SIGN_DATA = 0x33;
				bHDQ_ACCESS_FLAG1 |= BATT_EEPROM_RECALL;
				bErrorCheckCounter = 0;
			}
			bHDQ_ACCESS_FLAG1 |= BATT_ACR_BACKUP;
			break;

		case READ_ALL_BLOCK:
			bHDQ_ACCESS_FLAG |= BATT_EEPROM2_READ;
		case READ_TWO_BLOCK:
			inc_command_index();
			bHDQ_ACCESS_FLAG |= BATT_EEPROM0_READ;
			bHDQ_ACCESS_FLAG |= BATT_EEPROM1_READ;
			bErrorCheckCounter++;
			break;

		case BUS_WAIT_STATE:
			inc_command_index();
			break;

		case NET_ADDRESS:
			inc_command_index();
			bRecByteCnt = 0;
			bDataLengthBackUp = 0;
			OneWireSendByte(NET_ADDRESS);

//			bProcessOneWireIndex = ONEWIRE_HANG;
			break;

		case SKIP_NET_ADDR:
			inc_command_index();
			OneWireSendByte(SKIP_NET_ADDR);
			break;

		case COPY_DATA:
			inc_command_index();
			OneWireSendByte(COPY_DATA);
			break;

		case RECALL_DATA:
			inc_command_index();
			OneWireSendByte(RECALL_DATA);
			break;

		case WRITE_DATA:
			inc_command_index();
			bWriteDataLength = 0;
			OneWireSendByte(WRITE_DATA);
			break;

		case READ_DATA:
			inc_command_index();
			bRecByteCnt = 0;
			bDataLengthBackUp = 0;
			OneWireSendByte(READ_DATA);
			break;

		case POLL_DATA_INDEX: //polling battery data
			inc_command_index();
			OneWireSendByte(VOLTAGE_MSB_REG);
			bBatSRAMIndex = VOLTAGE_MSB_REG;
			bDataLength = 0x10;
			break;

		case EEPROM_BNK0_INDEX: //EEPROM bank0 data access
			inc_command_index();
			bHDQ_ACCESS_FLAG &= ~BATT_EEPROM0_UPDATE;
			bHDQ_ACCESS_FLAG &= ~BATT_EEPROM0_READ;
			// Make sure ESD dosen't cause us to go into
			// High speed mode.
			// See the ESD comment at the top of the file.
			GAUGE_CACHE[DS_PACK_INFO] = 0x6A;
			OneWireSendByte(EEPROM_BNK0);
			bBatSRAMIndex = EEPROM_BNK0;
			bDataLength = 0x20;
			break;

		case EEPROM_BNK1_INDEX: //EEPROM bank1 data access
			inc_command_index();
			bHDQ_ACCESS_FLAG &= ~BATT_EEPROM1_UPDATE;
			bHDQ_ACCESS_FLAG &= ~BATT_EEPROM1_READ;
			OneWireSendByte(EEPROM_BNK1);
			bBatSRAMIndex = EEPROM_BNK1;
			bDataLength = 0x20;
			break;

		case EEPROM_BNK2_INDEX: //EEPROM bank0 data access
			inc_command_index();
			bHDQ_ACCESS_FLAG &= ~BATT_EEPROM2_UPDATE;
			bHDQ_ACCESS_FLAG &= ~BATT_EEPROM2_READ;
			OneWireSendByte(EEPROM_BNK2);
			bBatSRAMIndex = EEPROM_BNK2;
			bDataLength = 0x20;
			break;

		case NET_ADDRESS_INDEX:
			inc_command_index();
			bDataLength = 0x08;
			break;

		case EEPROM_BNK21_INDEX: //EEPROM bank21 data access
			inc_command_index();
			OneWireSendByte(EEPROM_BNK2);
			bBatSRAMIndex = EEPROM_BNK2;
			bDataLength = 0x10;
			break;

		case BATT_REMAIN_ACR_INDEX:
			inc_command_index();
			bHDQ_ACCESS_FLAG &= ~BATT_ACR_UPDATE;
			GAUGE_CACHE[DS_BAT_REMAIN_ACR_MSB] = BATT_TEMP_ACR[0];
			GAUGE_CACHE[DS_BAT_REMAIN_ACR_LSB] = BATT_TEMP_ACR[1];
			print_tstamp();
			printf("GC RemACR <- %d\n",
				   ((unsigned int)BATT_TEMP_ACR[0])<<8|BATT_TEMP_ACR[1]);
			OneWireSendByte(DS_BAT_REMAIN_ACR_MSB);
			bBatSRAMIndex = DS_BAT_REMAIN_ACR_MSB;
			bDataLength = 2;
			break;

		case UPDATE_REAL_ACR:
			inc_command_index();
			bHDQ_ACCESS_FLAG1 &= ~BATT_REAL_ACR_UPDATE;
			GAUGE_CACHE[DS_ACR_MSB] = BATT_TEMP_REAL_ACR[0];
			GAUGE_CACHE[DS_ACR_LSB] = BATT_TEMP_REAL_ACR[1];
			OneWireSendByte(DS_ACR_MSB);
			bBatSRAMIndex = DS_ACR_MSB;
			print_tstamp();
			printf("GC rACR = BTRA: %d\n",
				   (((unsigned int)BATT_TEMP_REAL_ACR[0])<<8)|BATT_TEMP_REAL_ACR[1]);
			break;

		case BACKUP_ACR_INDEX:
			inc_command_index();
			bHDQ_ACCESS_FLAG1 &= ~BATT_ACR_BACKUP;
			OneWireSendByte(DS_ACR_MSB);
			bBatSRAMIndex = DS_ACR_MSB;
			bDataLength = 2;
			break;

		case LAST_ACR_INDEX:
			inc_command_index();
			bHDQ_ACCESS_FLAG1 &= ~BATT_LAST_ACR_UPDATE;
			mppt_nice_log();
			print_tstamp();
			printf("GC_LDACR=%d SOC = %u\n",last_dist_acr, (unsigned int)SOC);

			GAUGE_CACHE[DS_LAST_DISC_SOC] = SOC;
			GAUGE_CACHE[DS_LAST_DISC_ACR_MSB] = (unsigned char)(last_dist_acr >> 8);
			GAUGE_CACHE[DS_LAST_DISC_ACR_LSB] = (unsigned char)(last_dist_acr & 0x00FF);

			if (SOC > 50)
			{
				GAUGE_CACHE[DS_VALID_DISC_CYCLE] = 0;
			}

			if ( (SOC < 4) && (GAUGE_CACHE[DS_VALID_DISC_CYCLE] == 0) )
			{
				/* update storage count */
				GAUGE_CACHE[DS_VALID_DISC_CYCLE] = 1;
				GAUGE_CACHE[DS_STORAGE_ABUSE_CTR_LSB]++;
				if (GAUGE_CACHE[DS_STORAGE_ABUSE_CTR_LSB] == 0)
					GAUGE_CACHE[DS_STORAGE_ABUSE_CTR_MSB]++;
			}
			OneWireSendByte(DS_LAST_DISC_SOC);
			bBatSRAMIndex = DS_LAST_DISC_SOC;
			bDataLength = 4;
			break;

		case BACKUP_LAST_ACR:
			inc_command_index();
//			printf("test = %d\n",(((unsigned int)OneBattInfor[0])<<8)|OneBattInfor[1]);
			NewACR_BackUp_MSB = OneBattInfor[0];
			NewACR_BackUp_LSB = OneBattInfor[1];
			mppt_nice_log();
			print_tstamp();
			printf("BkLACR = %d\n",(((unsigned int)NewACR_BackUp_MSB)<<8)|NewACR_BackUp_LSB);
			break;

		case WAIT_WRITE_DCR:
			inc_command_index();
			if (bWriteDataLength < 0x02)
			{
				/* 0x20 ~ 0x21 */
				OneWireSendByte(BATT_TEMP_DCR[bWriteDataLength]);
				bWriteDataLength++;
				bCommandIndex--;
			}
			break;

		case WAIT_LAST_ACR_UPDATE:
			inc_command_index();
			if (bWriteDataLength < 0x04)
			{
				OneWireSendByte(GAUGE_CACHE[DS_LAST_DISC_SOC+bWriteDataLength]);
				bWriteDataLength++;
				bCommandIndex--;
			}
			break;

		case WAIT_WRITE_ACR:
			inc_command_index();
			if (bWriteDataLength < 0x02)
			{
				OneWireSendByte(BATT_TEMP_ACR[bWriteDataLength]);
				bWriteDataLength++;
				bCommandIndex--;
			}
			break;

		case WAIT_WRITE_REAL_ACR:
			inc_command_index();
			if (bWriteDataLength < 0x02)
			{
				OneWireSendByte(BATT_TEMP_REAL_ACR[bWriteDataLength]);
				bWriteDataLength++;
				bCommandIndex--;
			}
			break;

			/*
			case WAIT_WRITE_REINIT:
				{
				   if (bWriteDataLength < 96)
				   {
					OneWireSendByte(GAUGE_CACHE[EEPROM_BNK0+bWriteDataLength]);
					   bWriteDataLength++;
					   bCommandIndex--;
				   }
			   }
			   break;
			*/

		case WAIT_WRITE_BNK0:
		{
			inc_command_index();
			if (bWriteDataLength < 0x20)
			{
				bWriteCheckCache[bWriteDataLength] = GAUGE_CACHE[EEPROM_BNK0+bWriteDataLength];
				OneWireSendByte(GAUGE_CACHE[EEPROM_BNK0+bWriteDataLength]);
				bWriteDataLength++;
				bCommandIndex--;
			}
		}
		break;

		case WAIT_WRITE_BNK1:
		{
			inc_command_index();
			if (bWriteDataLength < 0x1F)  // keep INFO byte
			{
				bWriteCheckCache[bWriteDataLength] = GAUGE_CACHE[EEPROM_BNK1+bWriteDataLength];
				OneWireSendByte(GAUGE_CACHE[EEPROM_BNK1+bWriteDataLength]);
				bWriteDataLength++;
				bCommandIndex--;
			}
			else
			{
				if ((sMBAT_MISC & bat_update_all) != 0)
				{
					g_bUpdate	= 0;
					sMBAT_MISC &= ~bat_update_all;
					bWriteCheckCache[bWriteDataLength] = GAUGE_CACHE[EEPROM_BNK1+bWriteDataLength];
					OneWireSendByte(GAUGE_CACHE[EEPROM_BNK1+bWriteDataLength]);
				}
				else
				{
					bWriteCheckCache[bWriteDataLength] = GAUGE_CACHE[EEPROM_BNK1+bWriteDataLength];			// Backup 0x5f (battery ID)
				}
			}
		}
		break;

		case WAIT_WRITE_BNK2:
		{
			inc_command_index();
			if (bWriteDataLength < 0x20)
			{
				bWriteCheckCache[bWriteDataLength] = GAUGE_CACHE[EEPROM_BNK2+bWriteDataLength];
				OneWireSendByte(GAUGE_CACHE[EEPROM_BNK2+bWriteDataLength]);
				bWriteDataLength++;
				bCommandIndex--;
			}
		}
		break;

		case WAIT_BATT_DATA:
			inc_command_index();
			if (bDataLength != 0)
			{
				OneWireRecByte();
				bDataLength--;
				bDataLengthBackUp++;
				bCommandIndex--;
			}
			break;


			// +++ DAVID, 2007/4/26
		case UPDATE_NET_ADDRESS:
		{
			inc_command_index();
			printf("Found Bat: ");
			for ( i = 0; i < 8 ; i++ )
			{
				GAUGE_CACHE[DS_BAT_NET_ADDRESS+i] = OneBattInfor[i];
				printf("%02x ",(unsigned int)OneBattInfor[i]);
			}
			putchar('\n');
			HDQ_POLL_BATT_DATA(CHECK_REG_SETTINGS);
			w1_state_index = 0x1b;
			read_counter = 0;
			error_bank = 0;
		}
		break;

		case W1_UPDATE_EC_CACHE:
			inc_command_index();
			update_cache_values();
			break;

		case W1_CHECK_READING_VALID:
			switch ( check_reading_valid() )
			{
				case 0:
					update_cache_values();

					bProcessOneWireIndex = CALC_MOVING_AVG;
					bPollCheckCounter = 0;

// I think this is unnecessary now.
#if 0
					// Left overs from refactoring out UPDATE_*
					// TODO: figure out where this shoud really go
					if ((bHDQ_ACCESS_FLAG1 & BATT_REAL_ACR_UPDATE) != 0)
					{
						/* update cache data directly */
						GAUGE_CACHE[DS_ACR_MSB] = BATT_TEMP_REAL_ACR[0];
						GAUGE_CACHE[DS_ACR_LSB] = BATT_TEMP_REAL_ACR[1];
						print_tstamp();
						printf("Direct GCrACR = %d\n",
							   (((unsigned int)BATT_TEMP_REAL_ACR[0])<<8)|BATT_TEMP_REAL_ACR[1]);
					}
#endif
					break;

				case 1:
					bPollCheckCounter++;

					if (bPollCheckCounter > 3 )
					{
						SetAbnormalCauseCode( BATT_ERR_VOLT_INVALID );
						bProcessOneWireIndex = BATTERY_ERROR_STATE;
						break;
					}
					// End sequence and re-read
					inc_command_index();
					break;
			}
			break;

		case CALC_MOVING_AVG:
			inc_command_index();
			calcMovingAvg();
			break;

		case COMPARE_ACR:
			inc_command_index();
			bHDQ_ACCESS_FLAG1 &= ~BATT_ACR_CHECK;
			if ((BATT_TEMP_ACR[0] != OneBattInfor[0]) ||
					(BATT_TEMP_ACR[1] != OneBattInfor[1])
			   )
			{
				printf("S %d != T %d\n",
					   (((int)OneBattInfor)<<8)|OneBattInfor[1],
					   (((int)BATT_TEMP_ACR[0])<<8)|BATT_TEMP_ACR[1]);
				bHDQ_ACCESS_FLAG |= BATT_ACR_UPDATE;
			}
			else
				bHDQ_ACCESS_FLAG |= BATT_EEPROM0_READ;
			break;

		case BATTERY_ERROR_STATE:
			show_state_switches = 0;
			bProcessOneWireIndex = W1_IDLE;
			w1_state_index = 0x1a;
			HDQ_POLL_BATT_DATA(BATTERY_ERROR);
			break;

		case VALIDATE_BANK0:
			if ( check_bank0() )
			{
				error_bank = 1;
				read_counter++;
				print_tstamp();
				switch (read_counter)
				{
						// This case should never happen.
					case 0:
						puts("read0 counter==0? Error.\n");
						break;

					case 1:
						puts("bank 0 error. Retry\n");
						// retry
						HDQ_POLL_BATT_DATA(STARTUP_READ);
						break;

					case 2:
						puts("bank 0 error. Recall\n");
						// recall
						HDQ_POLL_BATT_DATA(RECALL_BANK0);
						break;

					default:
						puts("bank 0 error. halt\n");
						SetAbnormalCauseCode( BATT_ERR_BANK0 );
						bProcessOneWireIndex = BATTERY_ERROR_STATE;
						break;
				}
			}
			else
			{
				update_cache_values();
//			gc_dump_bank(0);
				printf("LDSOC = %u LDACR = %d\n",(unsigned int)GAUGE_CACHE[DS_LAST_DISC_SOC],
					   (((int)GAUGE_CACHE[DS_LAST_DISC_ACR_MSB]) << 8 )|GAUGE_CACHE[DS_LAST_DISC_ACR_LSB]
					  );

				if (error_bank == 1)
				{
					read_counter = 0;
					error_bank= 0;
				}
			}
			inc_command_index();
			break;

		case VALIDATE_BANK1:
			if ( check_bank1() )
			{
				error_bank = 2;
				read_counter++;
				print_tstamp();
				switch (read_counter)
				{
						// This case should never happen.
					case 0:
						printf("read1 counter==0? Error.\n");
						break;

					case 1:
						printf("bank 1 error. Retry\n");
						// retry
						HDQ_POLL_BATT_DATA(STARTUP_READ);
						break;

					case 2:
						printf("bank 1 error. Recall\n");
						// recall
						HDQ_POLL_BATT_DATA(RECALL_BANK1);
						break;

					default:
						puts("bank 1 error. halt");
						SetAbnormalCauseCode( BATT_ERR_BANK1 );
						bProcessOneWireIndex = BATTERY_ERROR_STATE;
						break;
				}
			}
			else
			{
				update_cache_values();
				if (error_bank == 2)
				{
					read_counter = 0;
					error_bank= 0;
				}
			}
			inc_command_index();
			break;

		case VALIDATE_BANK2:
			if ( check_bank2() )
			{
				error_bank = 3;
				read_counter++;
				print_tstamp();
				switch (read_counter)
				{
						// This case should never happen.
					case 0:
						printf("read2 counter==0? Bad mojo\n");
						break;

					case 1:
						printf("bank 2 error. Retry\n");
						// retry
						HDQ_POLL_BATT_DATA(STARTUP_READ);
						break;

					case 2:
						printf("bank 2 error. Recall\n");
						// recall
						HDQ_POLL_BATT_DATA(RECALL_BANK2);
						break;

					default:
						printf("bank 2 error. halt");
						SetAbnormalCauseCode( BATT_ERR_BANK2 );
						bProcessOneWireIndex = BATTERY_ERROR_STATE;
						break;
				}
			}
			else
			{
				update_cache_values();
				if (error_bank == 3)
				{
					read_counter = 0;
					error_bank= 0;
				}
			}
			inc_command_index();
			break;

		case SEED_AVERAGES:
			// MovingAvgCtr = 0;
			update_cache_values();
			calcMovingAvg();
			inc_command_index();
			break;

		case BATTERY_VALID:
			print_tstamp();
			puts("Battery Valid");
			battery_info |= BATTERY_VALID_FLAG;
			// Simulate old flags
			// TODO: fix so these are not nessary.
			sMBAT_STATUS |= bat_in;
			sMCHARGE_STATUS |= bat_wakeup;

			// We are done.  Start polling for VI data
			inc_command_index();
			break;

		case BANK0_RECALL_DONE:
			print_tstamp();
			puts("Recall Bank0");
			// retry
			HDQ_POLL_BATT_DATA(STARTUP_READ);
			inc_command_index();
			break;

		case BANK1_RECALL_DONE:
			print_tstamp();
			puts("Recall Bank1");
			// retry
			HDQ_POLL_BATT_DATA(STARTUP_READ);
			inc_command_index();
			break;

		case BANK2_RECALL_DONE:
			print_tstamp();
			puts("Recall Bank2");
			// retry
			HDQ_POLL_BATT_DATA(STARTUP_READ);
			inc_command_index();
			break;

		case READ_REGS_INDEX:
			inc_command_index();
			OneWireSendByte(EEPROM_REG);
			bBatSRAMIndex = EEPROM_REG;
			bDataLength = 0x02;
			break;

		case VALIDATE_REGS:
			if ( (OneBattInfor[0x00] != 0x38) ||
					(OneBattInfor[0x01] != 0xba) )
			{
				puts("Bad register settings. Fixing");
				HDQ_POLL_BATT_DATA(FIX_REGS);
			}
			else
			{
				HDQ_POLL_BATT_DATA(STARTUP_READ);
			}
			inc_command_index();
			break;

		case WRITE_REGS_INDEX:
			inc_command_index();
			OneWireSendByte(EEPROM_REG);
			bDataLength = 2;
			break;

		case WAIT_WRITE_REGS:
			inc_command_index();
			if (bWriteDataLength == 0x00)
			{
				OneWireSendByte(0x38);
				bWriteDataLength++;
				bCommandIndex--;
			}
			else
				if (bWriteDataLength == 0x01)
				{
					OneWireSendByte(0xba);
					bWriteDataLength++;
					bCommandIndex--;
				}
				else
				{
					HDQ_POLL_BATT_DATA(STARTUP_READ);
				}
			break;

#if 0
			// This is for use in debuging when you want the
			// state machine to stop in a single place
		case ONEWIRE_HANG:
			break;
#endif

		case HDQ_STOP:
			show_state_switches = 0;
			inc_command_index();

			// puts("HDQ_STOP-->BATT_HDQ_POLL");
			// Default operation is to poll the voltage, current, and temperature
			HDQ_POLL_BATT_DATA(BATT_HDQ_POLL);
			w1_state_index = 0x06;

			if ((sMCHARGE_STATUS & bat_wakeup) == 0)
			{
				/* gauge may not work */
				bHDQ_ACCESS_FLAG &= 0x70;     /* don't write */
				bHDQ_ACCESS_FLAG1 &= 0x91;    /* don't write */
				bEEPROM_WRITE_ALL = 0;
				wEEPROM_WR_TIME = 0;
			}

			if ((bHDQ_ACCESS_FLAG1 & BATT_EEPROM_RECALL) != 0)
			{
				/* recall all data while serial No. is wrong */
				bHDQ_ACCESS_FLAG1 &= ~BATT_EEPROM_RECALL;
				puts("EEPROM Recall");
				HDQ_POLL_BATT_DATA(RECALL_EEPROM2RAM);
				w1_state_index = 0x05;
				break;
			}
			if ((bHDQ_ACCESS_FLAG1 & BATT_ACR_BACKUP) != 0)
			{
				HDQ_POLL_BATT_DATA(BACKUP_REAL_ACR);
				w1_state_index = 0x03;
				break;
			}
			if ((bHDQ_ACCESS_FLAG & BATT_EEPROM2_READ) != 0)
			{
				HDQ_POLL_BATT_DATA(READ_EEPROM_BNK2);
				w1_state_index = 0x09;
				break;
			}
			if ((bHDQ_ACCESS_FLAG & BATT_EEPROM1_READ) != 0)
			{
				HDQ_POLL_BATT_DATA(READ_EEPROM_BNK1);
				w1_state_index = 0x08;
				break;
			}
			if ((bHDQ_ACCESS_FLAG & BATT_EEPROM0_READ) != 0)
			{
				HDQ_POLL_BATT_DATA(READ_EEPROM_BNK0);
				w1_state_index = 0x07;
				break;
			}

			/*******************************************************
			 *
			 * Everything below here is skipped if the battery is not valid.
			 * Its not safe to try and write to the battery if we are also
			 * in the process of trying to read and initialize the
			 * gauge cache.
			 *
			 *******************************************************/
			if (!(battery_info & BATTERY_VALID_FLAG) )
			{
				puts("!bvalid skip");
				break;
			}
			if ((bHDQ_ACCESS_FLAG1 & BATT_REAL_ACR_UPDATE) != 0)
			{
				HDQ_POLL_BATT_DATA(WRITE_BATT_REAL_ACR);
				w1_state_index = 0x12;
				break;
			}
			if ((bHDQ_ACCESS_FLAG & BATT_ACR_UPDATE) != 0)
			{
				bHDQ_ACCESS_FLAG1 |= BATT_ACR_CHECK;
				HDQ_POLL_BATT_DATA(WRITE_BATT_ACR);
				w1_state_index = 0x0d;
				break;
			}
			if ((bHDQ_ACCESS_FLAG & BATT_EEPROM0_UPDATE) != 0)
			{
				w1_state_index = 0x0a;
				if ((GAUGE_CACHE[DS_PACK_INFO] != 0x6A) )
				{
					// Rest the critical value and halt cause everything is unsafe
					GAUGE_CACHE[DS_PACK_INFO] = 0x6A;
					bEEPROM_WRITE_ALL = 0;
					SetAbnormalCauseCode( BATT_ERR_PACK_INFO );
				}
				else
				{
					HDQ_POLL_BATT_DATA(WRITE_EEPROM_BNK0);
					break;
				}
			}
			if ((bHDQ_ACCESS_FLAG & BATT_EEPROM1_UPDATE) != 0)
			{
				HDQ_POLL_BATT_DATA(WRITE_EEPROM_BNK1);
				w1_state_index = 0x0b;
				break;
			}
			if ((bHDQ_ACCESS_FLAG & BATT_EEPROM2_UPDATE) != 0)
			{
				HDQ_POLL_BATT_DATA(WRITE_EEPROM_BNK2);
				w1_state_index = 0x0c;
				break;
			}
			if ((bHDQ_ACCESS_FLAG1 & BATT_ACR_CHECK) != 0)
			{
				HDQ_POLL_BATT_DATA(COMPARE_ACR_VALUE);
				w1_state_index = 0x0e;
				break;
			}
			if ((bHDQ_ACCESS_FLAG1 & BATT_LAST_ACR_UPDATE) != 0)
			{
				HDQ_POLL_BATT_DATA(WRITE_LAST_ACR);
				w1_state_index = 0x04;
				break;
			}
			if (bEEPROM_WRITE_ALL != 0)
			{
				/* write all banks to EEPROM */
				if (bEEPROM_WRITE_ALL == 1)
				{
					w1_state_index = 0x14;
					if ((GAUGE_CACHE[DS_PACK_INFO] != 0x6A) )
					{
						// Reset the critical value and halt cause everything is unsafe
						GAUGE_CACHE[DS_PACK_INFO] = 0x6A;
						bEEPROM_WRITE_ALL = 0;
						SetAbnormalCauseCode( BATT_ERR_PACK_INFO );
					}
					else
					{
						HDQ_POLL_BATT_DATA(COPY_ALL_EEPROM);
					}
				}
				else if (bEEPROM_WRITE_ALL == 2)
				{
					if ((GAUGE_CACHE[DS_PACK_INFO] != 0x6A) )
					{
						// Reset the critical value and halt cause everything is unsafe
						GAUGE_CACHE[DS_PACK_INFO] = 0x6A;
						bEEPROM_WRITE_ALL = 0;
						SetAbnormalCauseCode( BATT_ERR_PACK_INFO );
					}
					else
					{
						HDQ_POLL_BATT_DATA(WRITE_EEPROM_BNK0);
						w1_state_index = 0x16;
					}
				}
				else if (bEEPROM_WRITE_ALL == 3)
				{
					HDQ_POLL_BATT_DATA(WRITE_EEPROM_BNK1);
					w1_state_index = 0x17;
				}
				else if (bEEPROM_WRITE_ALL == 4)
				{
					/* write data to gauge */
					if ((++GAUGE_CACHE[EEPROM_W_LSB]) == 0)
						GAUGE_CACHE[EEPROM_W_MSB]++;
					HDQ_POLL_BATT_DATA(WRITE_EEPROM_BNK2);
					w1_state_index = 0x18;
				}
				bEEPROM_WRITE_ALL--;
				wEEPROM_WR_TIME = 0;
				break;
			}
			if ((wEEPROM_WR_TIME) > EEPROM_WRITE_LOOPS)
			{
				/* one hour and no abnormal */
				if ((sMBAT_STATUS & bat_error) == 0)
				{
					bEEPROM_WRITE_ALL = 4;
					print_tstamp();
					puts("EEPROM write All");
				}
				break;
			}

			break;  // case HDQ_STOP:
	}
}

static unsigned char check_bank0(void)
{
	unsigned char i;

	// Verify the default status value
	if (OneBattInfor[0x11] != 0x6a )
	{
		printf("Incorrect status 0x%02x. Fixing.\n",(unsigned int)OneBattInfor[0x11]);
		OneBattInfor[0x11] = 0x6a;
		bHDQ_ACCESS_FLAG |= BATT_EEPROM0_UPDATE;
	}

	if (OneBattInfor[0x13] != 0x00 )
	{
		printf("Incorrect accumulation bias 0x%02x. Fixing.\n",(unsigned int)OneBattInfor[0x13]);
		OneBattInfor[0x13] = 0x00;
		bHDQ_ACCESS_FLAG |= BATT_EEPROM0_UPDATE;
	}

	if (OneBattInfor[0x14] != 0x01 )
	{
		printf("Incorrect discharge suspend 0x%02x. Fixing.\n",(unsigned int)OneBattInfor[0x14]);
		OneBattInfor[0x14] = 0x01;
		bHDQ_ACCESS_FLAG |= BATT_EEPROM0_UPDATE;
	}

	if (OneBattInfor[0x15] != 0x00 )
	{
		printf("Incorrect charge suspend 0x%02x. Fixing.\n",(unsigned int)OneBattInfor[0x15]);
		OneBattInfor[0x15] = 0x00;
		bHDQ_ACCESS_FLAG |= BATT_EEPROM0_UPDATE;
	}

	bBattDataFfCount = 0;
	for (i = 0; i < bDataLengthBackUp; i++)
	{
		if (OneBattInfor[i] == 0xFF)
		{
			bBattDataFfCount++;
		}
		else
		{
			bBattDataFfCount = 0;
		}

		if (bBattDataFfCount > 3)
		{
			puts("0xff count exceeded");
			puts("Bank 0 Data:");
			for (i = 0; i < bDataLengthBackUp; i++)
			{
				if ((i % 8) == 0)
				{
					printf("\n%02x: ",(unsigned int)i);
				}
				printf("%02x ",(unsigned int)OneBattInfor[i]);
			}
			puts("");
			return 1;
		}
	}
	return 0;
}

static unsigned char check_bank1(void)
{
	unsigned char i;

	// Check the battery type to see ifs a battery
	// we know about
	switch ( OneBattInfor[0x1f] )
	{
		case 0x11:
		case 0x12:
		case 0x22:
			break;

		default:
			puts("Unknown Battery Type");
			puts("Bank 1 Data:");
			for (i = 0; i < bDataLengthBackUp; i++)
			{
				if ((i % 8) == 0)
				{
					printf("\n%02x: ",(unsigned int)i);
				}
				printf("%02x ",(unsigned int)OneBattInfor[i]);
			}
			puts("");
			return 1;
	}

	bBattDataFfCount = 0;
	for (i = 0; i < bDataLengthBackUp; i++)
	{
		if (OneBattInfor[i] == 0xFF)
		{
			bBattDataFfCount++;
		}
		else
		{
			bBattDataFfCount = 0;
		}

		if (bBattDataFfCount > 3)
		{
			return 1;
		}
	}

	return 0;
}

static unsigned char check_bank2(void)
{
	unsigned char i;

	// Right now bank 2 doesn't have any
	// constant bytes.

	bBattDataFfCount = 0;
	for (i = 0; i < bDataLengthBackUp; i++)
	{
		if (OneBattInfor[i] == 0xFF)
		{
			bBattDataFfCount++;
		}
		else
		{
			bBattDataFfCount = 0;
		}

		if (bBattDataFfCount > 3)
		{
			return 1;
		}
	}

	return 0;
}

static void update_cache_values(void)
{
	unsigned char i;
	unsigned char j;
	j = bBatSRAMIndex;

	for (i = 0; i < bDataLengthBackUp; i++)
	{
		GAUGE_CACHE[i+j] = OneBattInfor[i];
	}
	bDataLengthBackUp = 0;
	bBatSRAMIndex = 0;
}

#ifdef UNUSED
void gc_dump_bank(unsigned char bank)
{
	unsigned char i, size;
	size = (0x20 * bank)+0x20;

	for (i = size; i < size+0x20; i++)
	{
		if ((i % 0x09)==0) printf("\n");
		printf("%02x:%02x ",(unsigned int)i,(unsigned int)GAUGE_CACHE[i]);
	}
	printf("\n");
}
#endif

// Sanity check the numbers we are reading.
static unsigned char check_reading_valid(void)
{
	unsigned char i;
	unsigned char j;
	int BatV;

	j = bBatSRAMIndex;

#ifdef NOT_USEFUL
	// Allows debug to override the voltage read from the battery.
	if (BvOverride & 0x01)
	{
		OneBattInfor[0] = (unsigned char)(BvValue>>8);
		OneBattInfor[1] = (unsigned char)(BvValue&0xff);
	}
#endif

	BatV = OneBattInfor[0] << 8 | OneBattInfor[1];

	// Max voltage from any of our chemistries is 8.5V
	// Battery voltage should never be negative
	// Anything < 0 or > 9 is a bogus read.
	if (BatV < 0 || BatV > mv_to_gauge(9000) )
	{
		printf("Invalid BatV %d\n",BatV);
		return 1;
	}

	for (i = 0; i < bDataLengthBackUp; i++)
	{
		GAUGE_CACHE[i+j] = OneBattInfor[i];
	}
	return 0;
}

/*
 * This works for the simple case but still has races. Because the the same
 * onewire read and write states are used in the reading and writing commands
 * there isn't any sort of completion flag. So these flags actually get cleared
 * just before the operation starts.
 *
 * FIXME:  Add some sort of flat that get set by each operation and isn't
 * cleard until it goes through the HDQ_STOP state.  Then add that
 * into the OR of flags that are cheked.
 *
*/
unsigned char onewire_operation_pending(void)
{
	if ( bHDQ_ACCESS_FLAG || bHDQ_ACCESS_FLAG1 || bEEPROM_WRITE_ALL )
	{
		return 1;
	}
	return 0;
}

unsigned char onewire_get_battery_type(void)
{
	return GAUGE_CACHE[DS_BAT_INFO];
}

void onewire_cmd_read_type(void)
{
	sdi_cmdresp_queue_add(GAUGE_CACHE[DS_BAT_INFO]);
}

void onewire_cmd_read_voltage(void)
{
	sdi_cmdresp_queue_add(GAUGE_CACHE[DS_VOLT_LSB]);
	sdi_cmdresp_queue_add(GAUGE_CACHE[DS_VOLT_MSB]);
}

void onewire_cmd_read_current(void)
{
	sdi_cmdresp_queue_add(GAUGE_CACHE[DS_CURT_LSB]);
	sdi_cmdresp_queue_add(GAUGE_CACHE[DS_CURT_MSB]);
}

void onewire_cmd_read_acr(void)
{
	sdi_cmdresp_queue_add(GAUGE_CACHE[DS_ACR_LSB]);
	sdi_cmdresp_queue_add(GAUGE_CACHE[DS_ACR_MSB]);
}

void onewire_cmd_read_temperature(void)
{
	sdi_cmdresp_queue_add(GAUGE_CACHE[DS_TEMP_LSB]);
	sdi_cmdresp_queue_add(GAUGE_CACHE[DS_TEMP_MSB]);
}

void onewire_cmd_read_status(void)
{
	unsigned char status = 0;
	signed int Ib;

	if (sMBAT_STATUS & bat_in)
	{
		status |= bs_bat_in;
	}
	if (sMBAT_STATUS & bat_full)
	{
		status |= bs_bat_full;
	}
	if (sMBAT_STATUS & bat_low)
	{
		status |= bs_bat_low;
	}
	if (sMBAT_STATUS & bat_error)
	{
		status |= bs_bat_error;
	}

	if (is_ac_adapter_in())
	{
		status |= bs_adapter_in;
	}

	if (sMCHARGE_STATUS & bat_WakeChg)
	{
		status |= bs_bat_trickle;
	}

	Ib = (GAUGE_CACHE[DS_CURT_MSB] << 8) | GAUGE_CACHE[DS_CURT_LSB];

	if (Ib < (signed int) cCURT_N_1_30)
	{
		status |= bs_bat_discharging;
	}
	else if ((Ib > (signed int) cCURT_1_30))
	{
		status |= bs_bat_charging;
	}

	sdi_cmdresp_queue_add(status);
}

void onewire_cmd_read_soc(void)
{
	sdi_cmdresp_queue_add(SOC);
}

void onewire_cmd_read_gauge_id(void)
{
	char i;
	for (i = 0; i < 8; i++)
	{
		sdi_cmdresp_queue_add(GAUGE_CACHE[DS_BAT_NET_ADDRESS+i]);
	}
}

void onewire_cmd_read_gauge_data(void)
{
	sdi_cmdresp_queue_add(GAUGE_CACHE[SDI_CMD_ARG(0)]);
}

void onewire_cmd_read_error_code(void)
{
	sdi_cmdresp_queue_add(bAbnormalCauseCode);
}

void onewire_cmd_read_battery_minW(void)
{
	sdi_cmdresp_queue_add(min_battery_power & 0xff);
	sdi_cmdresp_queue_add(min_battery_power >> 8);
}

void onewire_cmd_read_battery_maxW(void)
{
	sdi_cmdresp_queue_add(max_battery_power & 0xff);
	sdi_cmdresp_queue_add(max_battery_power >> 8);
}

void onewire_cmd_reset_battery_minmaxW(void)
{
	min_battery_power = max_battery_power = Pb_inst_in_mW;
}

void onewire_cmd_read_host_suspend_pwr(void)
{
	sdi_cmdresp_queue_add(host_suspend_power & 0xff);
	sdi_cmdresp_queue_add(host_suspend_power >> 8);
}
